package tourist

import (
	"apibe/grpc/rome/v1/share/config"
	"apibe/grpc/rome/v1/share/logger"
	"context"
	"database/sql"
	"github.com/go-redis/redis"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"strconv"
	"strings"
	"time"
)

// Init 池子初始化
func Init() {
	loadMongo() // mongo池子初始化
	loadRedis() // redis池子初始化
	loadMysql() // mysql池子初始化
}

// GetUrls 获取通用接口生成器
func GetUrls() interface{} {
	return urls
}

var urls = []struct {
	Value       string `json:"value"`
	Description string `json:"description"`
}{
	{"http://localhost:2288/v1/tourist/mongo/query_one", `面向 mongodb 的单行查询，基本查询格式是：{ "address": "masoner", "db": "apibe", "collection": "design", "filter": {}, "opinions": { "projection": { "api_name": 1 }, "sort": { "fix_date": -1 }, "skip": 1 } }`},
	{"http://localhost:2288/v1/tourist/mongo/query_many", `面向 mongodb 的多行查询，基本查询格式是：{ "address": "masoner", "db": "apibe", "collection": "design", "filter": {}, "opinions": { "projection": { "api_name": 1 }, "sort": { "fix_date": -1 }, "skip": 0, "limit": 2 } }`},
	{"http://localhost:2288/v1/tourist/mongo/update_one", `面向 mongodb 的单行修改，基本修改格式是：{ "address": "masoner", "db": "apibe", "collection": "design", "filter": { "api_name": "test_api4" }, "update": { "$set": { "api_name": "test_api4" } }, "opinions": { "upsert": false } }`},
	{"http://localhost:2288/v1/tourist/mongo/update_many", `面向 mongodb 的多行修改，基本修改格式是：{ "address": "masoner", "db": "apibe", "collection": "design", "filter": { "api_name": "test_api4" }, "update": { "$set": { "api_name": "test_api4" } }, "opinions": { "upsert": false } }`},
	{"http://localhost:2288/v1/tourist/mongo/create_one", `面向 mongodb 的单行创建，基本修改格式是：{ "address": "masoner", "db": "test", "collection": "test", "insert": { "name": "root", "account": "root", "password": "root" } }`},
	{"http://localhost:2288/v1/tourist/mongo/create_many", `面向 mongodb 的多行创建，基本修改格式是：{ "address": "masoner", "db": "test", "collection": "test", "insert": [ { "name": "root", "account": "root", "password": "root" }, { "name": "root", "account": "root", "password": "root" } ] }`},
	{"http://localhost:2288/v1/tourist/mongo/remove_one", `面向 mongodb 的单行删除，基本修改格式是：{ "address": "masoner", "db": "test", "collection": "test", "filter": { "account": "root" } }`},
	{"http://localhost:2288/v1/tourist/mongo/remove_many", `面向 mongodb 的多行删除，基本修改格式是：{ "address": "masoner", "db": "test", "collection": "test", "filter": { "account": "root" } }`},
	{"http://localhost:2288/v1/tourist/redis/set_one", `面向 redis 的单行插入，基本修改格式是：{ "address": "masoner0", "key": "1", "value": "test", "second": 10000 }`},
	{"http://localhost:2288/v1/tourist/redis/set_many", `面向 redis 的多行插入，基本修改格式是：{ "set": [ { "address": "masoner0", "key": "11", "value": "test", "second": 10000 }, { "address": "masoner0", "key": "14", "value": "test", "second": 10000 } ] }`},
	{"http://localhost:2288/v1/tourist/redis/get_one", `面向 redis 的单行查询，基本修改格式是：{ "address":"masoner0", "key":"1" }`},
	{"http://localhost:2288/v1/tourist/redis/get_many", `面向 redis 的多行匹配查询，基本修改格式是：{ "address": "masoner0", "key": "1*" }`},
	{"http://localhost:2288/v1/tourist/redis/del_one", `面向 redis 的单行删除，基本修改格式是：{ "address": "masoner0", "key": "1" }`},
	{"http://localhost:2288/v1/tourist/redis/del_many", `面向 redis 的多行删除，基本修改格式是：{ "address": "masoner0", "key": "1*" }`},
	{"http://localhost:2288/v1/tourist/mysql/select_one", `面向 mysql 的单行查询，基本修改格式是：{ "address": "masoner", "column": [ "account", "password", "id" ], "sql": "SELECT account,password,id FROM apibe WHERE id = ? AND account=?", "argument": [ 1, "root3" ] }`},
	{"http://localhost:2288/v1/tourist/mysql/select_many", `面向 mysql 的多行查询，基本修改格式是：{ "address": "masoner", "column": [ "account", "password", "id" ], "sql": "SELECT account,password,id FROM apibe WHERE id > ?", "argument":[ 0 ] }`},
	{"http://localhost:2288/v1/tourist/mysql/exec_one", `面向 mysql 的单行CUD，基本修改格式是：{ "address": "masoner", "sql": "INSERT INTO apibe (name,password,account) VALUES (?,?,?)", "argument": [ "root1", "root2", "root3" ] }`},
	{"http://localhost:2288/v1/tourist/mysql/exec_many", `面向 mysql 的多行CUD，基本修改格式是：{ "address": "masoner", "exec": [ { "sql": "INSERT INTO apibe (name,password,account) VALUES (?,?,?)", "argument": [ "root1", "root1", "root1" ] }, { "sql": "INSERT INTO apibe (name,password,account) VALUES (?,?,?)", "argument": [ "root2", "root2", "root2" ] } ], "dis_rollback": false, "disconnect": false }`},
}

var Pool = &pool{
	Mongo: map[string]*mongo.Client{},
	Mysql: map[string]*sql.DB{},
	Redis: map[string]*redis.Client{},
}

var poolConf = config.Config.Plugin.Tourist

type pool struct {
	Mongo map[string]*mongo.Client
	Mysql map[string]*sql.DB
	Redis map[string]*redis.Client
}

func loadMongo() {
	// 1. 定期ping、用来清除无效的连接
	for k, client := range Pool.Mongo {
		err := client.Ping(context.Background(), nil)
		if err != nil {
			delete(Pool.Mongo, k)
		}
	}
	// 2. 如果当前连接已经被放进了池子,就从配置中清除
	for k, _ := range config.Config.Plugin.Tourist.Mongo {
		for k1, _ := range Pool.Mongo {
			if k == k1 {
				delete(config.Config.Plugin.Tourist.Mongo, k)
				continue
			}
		}
	}
	// 3. 对不在池子里的(新|断开 的)数据库进行连接
	timeout := time.Second * 30
	var maxPoolSize uint64 = 100
	var minPoolSize uint64 = 20
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	for k, url := range config.Config.Plugin.Tourist.Mongo {
		o := options.Client().ApplyURI(url)
		o.SetMinPoolSize(minPoolSize)
		o.SetMaxPoolSize(maxPoolSize)
		client, err := mongo.Connect(ctx, o)
		if err != nil {
			logger.Logger.Errorf("poll init err , mongo: %v is not surpport ,hope address like (mongodb://root:Xu598587358,.@49.232.220.204:27017/admin?authSource=admin) ", url)
			continue
		}
		Pool.Mongo[k] = client
	}
}

func loadRedis() {
	// 1. 定期ping、用来清除无效的连接
	for k, client := range Pool.Redis {
		err := client.Ping()
		if err != nil {
			delete(Pool.Mongo, k)
		}
	}
	// 2. 如果当前连接已经被放进了池子,就从配置中清除
	for k, _ := range config.Config.Plugin.Tourist.Redis {
		for k1, _ := range Pool.Redis {
			if k == k1 {
				delete(config.Config.Plugin.Tourist.Redis, k)
				continue
			}
		}
	}
	// 3. 新连接
	for k, address := range config.Config.Plugin.Tourist.Redis {
		opt := &redis.Options{}
		split := strings.Split(address, "@")
		if len(split) == 2 {
			opt.Password = strings.TrimPrefix(split[0], "auth:")
			addressAndDb := strings.Split(split[1], "/")
			if len(addressAndDb) == 2 {
				opt.Addr = addressAndDb[0]
				db, err := strconv.Atoi(addressAndDb[1])
				if err != nil {
					logger.Logger.Errorf("poll init err , redis: %v is not surpport, hope address like (auth:password@127.0.0.1:3306/0)", address)
					continue
				}
				opt.DB = db
			} else {
				logger.Logger.Errorf("redisPool init err , redis: %v is not surpport, hope address like (auth:password@127.0.0.1:3306/0)", address)
				continue
			}
		}
		client := redis.NewClient(opt)
		if client.Ping().Err() == nil {
			Pool.Redis[k] = client
		}
	}
}

func loadMysql() {
	// 1. 定期ping、用来清除无效的连接
	for k, client := range Pool.Mysql {
		err := client.Ping()
		logger.Logger.Errorf("mysqlPool init Err: %v ping failed, hope address like (account:password@tcp(ip:port)/database)", k)
		if err != nil {
			delete(Pool.Mysql, k)
		}
	}
	// 2. 如果当前连接已经被放进了池子,就从配置中清除
	for k, _ := range config.Config.Plugin.Tourist.Mysql {
		for k1, _ := range Pool.Mysql {
			if k == k1 {
				delete(config.Config.Plugin.Tourist.Mysql, k)
				continue
			}
		}
	}
	//3. 新连接
	for k, address := range config.Config.Plugin.Tourist.Mysql {
		db, err := sql.Open("mysql", address)
		if err != nil {
			logger.Logger.Errorf("mysqlPool init Err: %v is not surpport, hope address like (account:password@tcp(ip:port)/database)", address)
			continue
		}
		db.SetMaxOpenConns(100)
		db.SetMaxIdleConns(10)
		// 尝试与数据库建立连接（校验dsn是否正确）
		if db.Ping() == nil {
			Pool.Mysql[k] = db
		} else {
			logger.Logger.Errorf("mysqlPool init Err: %v ping failed, hope address like (account:password@tcp(ip:port)/database)", address)
		}
	}
}
